const mongoose = require('mongoose')
const Schema = mongoose.Schema
const Mixed = Schema.Types.Mixed
const SALT_WORK_FACTOR = 10
const MAX_LOGIN_ATTEMPTS = 5
const LOCK_TIME = 2 * 60 * 60 * 1000
const bcrypt = require("bcrypt")

const UserSchema = new Schema({
    username: {
        unique: true,
        required: true,
        type: String
    },
    email: {
        unique: true,
        required: true,
        type:String
    },
    password: {
        type:String
    },
    loginAttempts:{
        type: Number,
        required: true,
        default: 0
    },
    lockUntil: {
        type: Number
    },
    meta: {
        createdAt: {
            type: Date,
            default: Date.now()
        },
        updatedAt: {
            type: Date,
            default: Date.now()
        }
    }
})

UserSchema.virtual('isLocked').get(function(){
    return !!(this.lockUntil && this.lockUntil > Date.now())
})

UserSchema.pre("save", function(next){
    if (this.isNew) {
        this.meta.createdAt = this.meta.updatedAt = Date.now()
    } else {
        this.meta.updatedAt = Date.now()
    }
    next()
})

UserSchema.pre("save", function(next){
    if (!this.isModified('password')) return next()

    bcrypt.genSalt(SALT_WORK_FACTOR, (err, salt)=>{
        if (err) return next(err)

        bcrypt.hash(user.password, salt, (err,hash)=>{
            if(err) return next(err)

            this.password = hash

            next()
        })
    })
    next()
})

UserSchema.methods = {
    comparePassword: (_password, password)=>{
        return new Promise((resolve, reject)=>{
            bcrypt.compare(_password, password, (err, isMatch)=>{
                if (!err) resolve(isMatch)
                else reject(err)
            })
        })
    },
    incLoginAttepts: (user) =>{
        return new Promise((resolve, reject)=>{
            if (this.lockUntil && this.lockUntil < Date.now()){
                this.update({
                    $set: {
                        loginAttempts: 1
                    },
                    $unset:{
                        lockUntil: 1
                    }
                }, err => {
                    if (!err) resolve(true)
                    else reject(err)
                })
            } else {
                let update = {
                    $inc: {
                        loginAttempts: 1
                    }
                }
                if (this.loginAttempts + 1 >= MAX_LOGIN_ATTEMPTS&&!this.isLocked) {
                    updates.$set = {
                        lockUntil: Date.now() + LOCK_TIME
                    }
                }
                this.update(update, err=>{
                    if (!err) resolve(true)
                    else reject(err)
                })
            }
        })
        
    }
}

mongoose.model("User", UserSchema)